package nio.three;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
    通过NIO实现非阻塞式群聊系统--服务端
 */
public class Server {
    //存储所有注册到这个选择器上的所有客户端通道
//    private static final List<SocketChannel> scs = new ArrayList<>();

    public static void main(String[] args) {
        try {
            //创建服务端通道
            ServerSocketChannel ssc = ServerSocketChannel.open();
            //设置为非阻塞
            ssc.configureBlocking(false);
            //设置端口号
            ssc.bind(new InetSocketAddress(8888));
            //创建选择器
            Selector selector = Selector.open();
            //将服务端通道注册到选择器上,监听所有客户端的接入
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            //使用选择器轮询所有接入到这个选择器上的客户端通道
            while (selector.select() > 0) {
                //得到所有的事件的迭代器
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                //遍历得到所有事件
                while (iterator.hasNext()) {
                    //得到当前事件
                    SelectionKey sk = iterator.next();
                    if (sk.isAcceptable()) {  //当前是个监听事件
                        //将监听到的客户端管道注册到选择器上
                        SocketChannel sc = ssc.accept();
                        sc.configureBlocking(false);
                        //将当前客户端设置为可读可写
                        sc.register(selector, SelectionKey.OP_READ);
                        //将这个客户端通道保存起来
//                        scs.add(sc);
//                        System.out.println("有"+scs.size()+"个客户端连接");
                    } else if (sk.isReadable()) { //如果当前是读事件
                        System.out.println("某个客户端发送了消息");
                        //获取当前读事件通道
                        SocketChannel sc = (SocketChannel) sk.channel();
                        //读取客户端的消息
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        sc.read(buffer);
                        //切换为读模式
                        buffer.flip();
                        buffer.mark(); //标记到0位置
                        //将读取到的消息发送到所有的客户端
                        for (SelectionKey key : selector.keys()) {
                            SelectableChannel channel = key.channel();
                            //该通道不是服务端通道和当前通道
                            if (channel != sc && channel != ssc) {
                                //将消息发送给这个通道
                                ((SocketChannel) channel).write(buffer);
                                buffer.reset();
                            }
                        }
                    }
                    //处理完这个事件后删除
                    iterator.remove();
                }
            }
        } catch (IOException e) {
            System.out.println("异常退出");
            e.printStackTrace();
        }
    }
}
